import mx.utils.Delegate;

import gugga.sequence.TaskManagerItem;
import gugga.sequence.FictiveTask;
import gugga.sequence.ExecuteAsyncMethodTask;
import gugga.common.EventDescriptor;
import gugga.common.ITask;

import guggaLibTests.support.TaskExecutionEvaluator;
import guggaLibTests.support.PauseResumeMethodsSequence;

import test_framework.test.unit.TestCase;

/**
 * @author vladimir
 */
class guggaLibTests.TaskManagerItemTest 
		extends TestCase
{
	private var currentDelayID:Number;
	private var currentTaskManagerItem:TaskManagerItem;
	
	private var delayInterval:Number;
	
	public function TaskManagerItemTest()
	{
		super();
		
		this.delayInterval = 1000;
	}
	
	public function testConstructor()
	{
		var fictiveTask:ITask = new FictiveTask();
		
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		
		assertNotNull(
				"taskManagerItem should not be null after creation", 
				taskManagerItem);
		assertNotUndefined(
				"taskManagerItem should not be undefined after creation", 
				taskManagerItem);
		
		var scheduledTask:ITask = taskManagerItem.ScheduledTask;
		assertNotNull(
				"taskManagerItem.ScheduledTask should not be null after creation", 
				scheduledTask);
		assertNotUndefined(
				"taskManagerItem.ScheduledTask should not be undefined after creation", 
				scheduledTask);
		assertEquals(
				"taskManagerItem.ScheduledTask should match the task specified in the constructor's arguments",
				scheduledTask, 
				fictiveTask);
	}
	
	public function testStartWithoutPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		taskManagerItem.start();
		
		// there are no preconditions needed to be met, so start event should 
		// be fired:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testStartWithAcceptingPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
				
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		
		taskManagerItem.addPrecondition(precondition);
		
		taskManagerItem.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("precondition still not met, so the taskManagerItem should not be started yet");
		
		// meet the needed precondition:
		fictiveEventSource.start();
		
		// all preconditions were met, so start event should be fired:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testStartWithUnacceptingPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var isAccepting:Boolean = false;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
				
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		
		taskManagerItem.addPrecondition(precondition);
		
		taskManagerItem.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("precondition still not met, so the taskManagerItem should not be started yet");
		
		// try to meet the needed precondition:
		fictiveEventSource.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("precondition still not met, taskManager's state is unaccepting, so taskManagerItem should not be started yet");
	}
	
	/**
	 * TODO: this test should be changed when the new behaviour of the 
	 * <code>PreconditionsManager.reset()</code> is introduced.
	 */
	public function testStartInterruptStart()
	{
		// initialize TaskExecutionEvaluator:
		var evaluatorBeforeInterrupt:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		var evaluatorAfterInterrupt:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		
		// test portion before interrupt:
		evaluatorBeforeInterrupt.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeInterrupt, 
						evaluatorBeforeInterrupt.onTaskStarted));
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(
						evaluatorAfterInterrupt, 
						evaluatorAfterInterrupt.onTaskStarted));
		
		// create an unaccepting taskManagerItem:
		var isAccepting:Boolean = false;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeInterrupt, 
						evaluatorBeforeInterrupt.onTaskStarted));
		taskManagerItem.addEventListener(
				"interrupted", 
				Delegate.create(
						evaluatorBeforeInterrupt, 
						evaluatorBeforeInterrupt.onTaskInterrupted));
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(
						evaluatorAfterInterrupt, 
						evaluatorAfterInterrupt.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		
		taskManagerItem.start();
		evaluatorBeforeInterrupt.assertTaskStatusRegisterIsEmpty("precondition1 still not met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.interrupt();
		evaluatorBeforeInterrupt.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"interrupted"});
			
		evaluatorBeforeInterrupt.pauseToEvaluateTaskExecution();
		
		// test portion after interrupt:
		evaluatorAfterInterrupt.setDelayedEvaluation(this.delayInterval);
		
		taskManagerItem.start();
		/**
		 * After <code>interrupt()</code> the state of the 
		 * <code>taskManagerItem</code> is 
		 * <code>TaskManagerItemStates.Interrupted</code>. This state will 
		 * cause the execution of the <code>reset()</code> method on the 
		 * following <code>start()</code>. Because of the behaviour of 
		 * <code>PreconditionsManager.reset()</code> we can inspect the 
		 * following side effect.
		 * <p> 
		 * After creation <code>taskManagerItem</code> is 
		 * <b><i>unaccepting</i></b>, and the added <code>precondition1</code> 
		 * is also <b><i>unaccepting</i></b> - it will ignore any events 
		 * comming from <code>fictiveEventSource1</code>. After 
		 * <code>reset()</code> <code>taskManagerItem</code> will be still 
		 * <b><i>unaccepting</i></b>, and all newly added preconditions will be 
		 * also <b><i>unaccepting</i></b>, but surprisingly 
		 * <code>precondition1</code> now is <b><i>accepting</i></b> and will 
		 * receive events comming from <code>fictiveEventSource1</code>.
		 * 
		 * @see gugga.sequence.PreconditionsManager.reset()
		 */
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition2);
		
		// meet precondition1 (now it should be accepting):
		fictiveEventSource1.start();
		evaluatorAfterInterrupt.assertTaskStatusRegisterIsEmpty("precondition1 was met, but precondition2 still not met, so the taskManagerItem should not be started yet");
		
		fictiveEventSource2.start();
		evaluatorAfterInterrupt.assertTaskStatusRegisterIsEmpty("precondition2 is still unaccepting and still not met, so the taskManagerItem should not be started yet");
		
		// in order to meet precondition2, it should be explicitly accepted:
		taskManagerItem.acceptPrecondition(precondition2);
		// now we can meet precondition2:
		fictiveEventSource2.start();
		
		// all preconditions were met:
		evaluatorAfterInterrupt.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"start"});
		evaluatorAfterInterrupt.registerRequiredTaskStatus
				({task:fictiveTask, event:"start"});
		
		evaluatorAfterInterrupt.pauseToEvaluateTaskExecution();
	}
	
	public function testAddRemovePrecondition()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("precondition1 still not met, so the taskManagerItem should not be started yet");
		
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition2);
		evaluator.assertTaskStatusRegisterIsEmpty("precondition2 added and all preconditions are still not met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.removePrecondition(precondition2);
		evaluator.assertTaskStatusRegisterIsEmpty("precondition2 removed and precondition1 still not met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.removePrecondition(precondition1);
		// all preconditions were removed, so the preconditionsTask should be 
		// completed, and taskManagerItem should start too:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testRemovePreconditionsByEventSource()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		// both preconditions have the same event source:
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("no preconditions were met, so the taskManagerItem should not be started yet");
		
		// this should remove precondition1 and precondition2, because they 
		// share a same event source:
		taskManagerItem.removePreconditionsByEventSource(fictiveEventSource);
		
		// all preconditions were removed, so the preconditionsTask should be 
		// completed, and taskManagerItem should start too:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testAcceptPrecondition()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an unaccepting taskManagerItem:
		var isAccepting:Boolean = false;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and no preconditions were met, so the taskManagerItem should not be started yet");
		
		// try to meet the needed preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and no preconditions are accepted yet, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptPrecondition(precondition1);
		fictiveEventSource1.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and only precondition1 is met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptPrecondition(precondition2);
		fictiveEventSource2.start();
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testAcceptPreconditionByEventSource()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an unaccepting taskManagerItem:
		var isAccepting:Boolean = false;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		// both precondition1 and precondition2 have the same event source:
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition3:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		taskManagerItem.addPrecondition(precondition3);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and no preconditions were met, so the taskManagerItem should not be started yet");
		
		// try to meet the needed preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and no preconditions are accepted yet, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptPreconditionsByEventSource(fictiveEventSource1);
		fictiveEventSource1.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and only precondition1 and precondition2 are met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptPreconditionsByEventSource(fictiveEventSource2);
		fictiveEventSource2.start();
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testAcceptAllPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an unaccepting taskManagerItem:
		var isAccepting:Boolean = false;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and no preconditions were met, so the taskManagerItem should not be started yet");
		
		// try to meet the needed preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is unaccepting and no preconditions are accepted yet, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptAllPreconditions();
		
		// meet precondition1:
		fictiveEventSource1.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is accepting but only precondition1 is met, so the taskManagerItem should not be started yet");
		
		// meet precondition2:
		fictiveEventSource2.start();
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testIgnorePrecondition()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is accepting, but no preconditions were met, so the taskManagerItem should not be started yet");
		
		// ignore precondition1:
		taskManagerItem.ignorePrecondition(precondition1);
		
		// try to meet all preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is ignoring precondition1 and only precondition2 should be met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptPrecondition(precondition1);
		// now we should be able to meet precondition1:
		fictiveEventSource1.start();
		
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testIgnorePreconditionByEventSource()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		// both precondition1 and precondition2 have the same event source:
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition3:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		taskManagerItem.addPrecondition(precondition3);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is accepting, but no preconditions were met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.ignorePreconditionsByEventSource(fictiveEventSource1);
		
		// try to meet all preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is ignoring precondition1 and only precondition2 should be met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptPreconditionsByEventSource(fictiveEventSource1);
		// now we should be able to meet precondition1 and precondition2:
		fictiveEventSource1.start();
		
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testIgnoreAllPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is accepting, but no preconditions were met, so the taskManagerItem should not be started yet");
		
		taskManagerItem.ignoreAllPreconditions();
		
		// try to meet all preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is started, but it is ignoring all preconditions, so the taskManagerItem should not be started yet");
		
		taskManagerItem.acceptAllPreconditions();
		// now we should be able to meet all preconditions:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	/**
	 * assure that <code>isImmediatelyInterruptable()</code> always returns 
	 * <code>true</code>, unless <code>taskManagerItem</code> is not in the 
	 * <code>TaskManagerItemStates.Running</code> state.
	 */
	public function testIsImmediatelyInterruptableWhenNotRunning()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		fictiveTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		taskManagerItem.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		assertTrue(
				"taskManagerItem is not started yet, so isImmediatelyInterruptable() should return true",
				taskManagerItem.isImmediatelyInterruptable()
				&& evaluator.assertTaskStatusRegisterIsEmpty());
				
		taskManagerItem.start();
		
		// there are no preconditions, so the taskManagerItem and fictiveTask 
		// should be started:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		// and because of the immediately completion of fictiveTask, 
		// taskManagerItem should be completed too:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"completed"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"completed"});
		
		evaluator.pauseToEvaluateTaskExecution();
		
		assertTrue(
				"taskManagerItem is completed, so isImmediatelyInterruptable() should return true, because taskManagerItem is no more in running state",
				taskManagerItem.isImmediatelyInterruptable());
	}
	
	/**
	 * Assure that <code>isImmediatelyInterruptable()</code> returns 
	 * <code>mScheduledTask.isImmediatelyInterruptable()</code>, if 
	 * <code>taskManagerItem</code> is in 
	 * <code>TaskManagerItemStates.Running</code> state. 
	 */
	public function testIsImmediatelyInterruptableWhenRunning()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		// prepare asynchonous task:
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		var asynchronousTask:ITask = ExecuteAsyncMethodTask.create(
				eventDescriptor,
				this,
				this.triggerEmptyFunction,
				[]);
		asynchronousTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				asynchronousTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		assertTrue(
				"taskManagerItem is not started yet, so isImmediatelyInterruptable() should return true",
				taskManagerItem.isImmediatelyInterruptable()
				&& evaluator.assertTaskStatusRegisterIsEmpty());
		
		taskManagerItem.start();
		
		// there are no preconditions, so the taskManagerItem and fictiveTask 
		// should be started:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:asynchronousTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
		
		// taskManagerItem should be in running state now, and 
		// isImmediatelyInterruptable() should return the value of 
		// asynchronousTask.isImmediatelyInterruptable():
		this.currentDelayID = setInterval(
				this, 
				"assertIsImmediatelyInterruptableWhenRunning", 
				this.delayInterval);
		
		this.currentTaskManagerItem = taskManagerItem;
		
		this.pause();
	}
	
	private function triggerEmptyFunction()
	{
		// EMPTY FUNCTION!!!
		// this function should usually raise the event needed for the 
		// ExecuteAsyncMethodTask
	}
	
	private function assertIsImmediatelyInterruptableWhenRunning()
	{
		clearInterval(this.currentDelayID);
		
		assertEquals(
				"TaskManagerItem.isImmediatelyInterruptable() should equals TaskManagerItem.ScheduledTask.isImmediatelyInterruptable() when in running state",
				this.currentTaskManagerItem.isImmediatelyInterruptable(), 
				this.currentTaskManagerItem.ScheduledTask.isImmediatelyInterruptable());
		
		this.resume();
	}
	
	public function testInterruptBeforeStart()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var fictiveTask:ITask = new FictiveTask();
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		taskManagerItem.interrupt();
		
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"interrupted"});
		
		evaluator.evaluateTaskExecution();
	}
	
	public function testInterruptWhenNotRunning()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var fictiveTask:ITask = new FictiveTask();
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		
		taskManagerItem.addPrecondition(precondition);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is started, but no preconditions were met, so the taskManagerItem should not be in running state");
		
		taskManagerItem.interrupt();
		
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"interrupted"});
		
		evaluator.evaluateTaskExecution();
	}
	
	public function testInterruptAfterCompleted()
	{
		// initialize TaskExecutionEvaluators:
		var evaluatorBeforeCompleted:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		var evaluatorAfterCompleted:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
			
		evaluatorBeforeCompleted.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeCompleted, 
						evaluatorBeforeCompleted.onTaskStarted));
		fictiveTask.addEventListener(
				"completed", 
				Delegate.create(
						evaluatorBeforeCompleted, 
						evaluatorBeforeCompleted.onTaskCompleted));
		fictiveTask.addEventListener(
				"interrupted", 
				Delegate.create(
						evaluatorAfterCompleted, 
						evaluatorAfterCompleted.onTaskInterrupted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeCompleted, 
						evaluatorBeforeCompleted.onTaskStarted));
		taskManagerItem.addEventListener(
				"completed", 
				Delegate.create(
						evaluatorBeforeCompleted, 
						evaluatorBeforeCompleted.onTaskCompleted));
		taskManagerItem.addEventListener(
				"interrupted", 
				Delegate.create(
						evaluatorAfterCompleted, 
						evaluatorAfterCompleted.onTaskInterrupted));
				
		taskManagerItem.start();
		
		evaluatorBeforeCompleted.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"start"});
		evaluatorBeforeCompleted.registerRequiredTaskStatus(
				{task:fictiveTask, event:"start"});
		evaluatorBeforeCompleted.registerRequiredTaskStatus(
				{task:fictiveTask, event:"completed"});
		evaluatorBeforeCompleted.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"completed"});
		
		evaluatorBeforeCompleted.pauseToEvaluateTaskExecution();
		
		// here taskManagerItem should has been already completed:
		evaluatorAfterCompleted.setDelayedEvaluation(this.delayInterval);
		
		taskManagerItem.interrupt();
		
		evaluatorAfterCompleted.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"interrupted"});
		
		evaluatorAfterCompleted.pauseToEvaluateTaskExecution();
	}
	
	/**
	 * TODO: These 2-part tests should be revised, and redesigned!!!
	 * <p> 
	 * Main reasons:
	 * <ul>
	 * 	<li><code>pause()</code> does not stop the execution of the test run</li>
	 * 	<li><code>pause()</code> delays the finishing of the test run</li>
	 * 	<li>the test run will finish, only after <code>resume()</code></li>
	 * 	<li>the instructions right after <code>pause()</code> will be executed without waiting for <code>resume()</code></li>
	 * </ul>
	 * <p>
	 * Assure <code>interrupt()</code> behaviour when 
	 * <code>taskManagerItem</code> is in 
	 * <code>TaskManagerItemStates.Running</code> state. To accomplish this 
	 * test execution of an asynchronous task is needed.
	 */
	/*public function testInterruptWhenRunning()
	{
		// initialize TaskExecutionEvaluators:
		var evaluatorBeforeStart:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		var evaluatorAfterStart:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		
		// test portion before start():
		evaluatorBeforeStart.setDelayedEvaluation(this.delayInterval);
		
		// prepare asynchonous task:
		var fictiveEventSource:FictiveTask = new FictiveTask();
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		var asynchronousTask:ITask = ExecuteAsyncMethodTask.create(
				eventDescriptor,
				this,
				this.triggerEmptyFunction,
				[]);
		asynchronousTask.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeStart, 
						evaluatorBeforeStart.onTaskStarted));
		asynchronousTask.addEventListener(
				"interrupted", 
				Delegate.create(
						evaluatorAfterStart, 
						evaluatorAfterStart.onTaskInterrupted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				asynchronousTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeStart, 
						evaluatorBeforeStart.onTaskStarted));
		taskManagerItem.addEventListener(
				"interrupted", 
				Delegate.create(
						evaluatorAfterStart, 
						evaluatorAfterStart.onTaskInterrupted));
		
		taskManagerItem.start();
		
		// there are no preconditions, so the taskManagerItem and fictiveTask 
		// should be started, taskManagerItem should be in running state now:
		evaluatorBeforeStart.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"start"});
		evaluatorBeforeStart.registerRequiredTaskStatus(
				{task:asynchronousTask, event:"start"});
		
		evaluatorBeforeStart.pauseToEvaluateTaskExecution();
		
		// test portion after start():
		evaluatorAfterStart.setDelayedEvaluation(this.delayInterval);
				
		// these events should happen after interrupt, asynchronous task still 
		// not completed, and taskManagerItem should still be in running state:
		evaluatorAfterStart.registerRequiredTaskStatus(
				{task:taskManagerItem, event:"interrupted"});
		evaluatorAfterStart.registerRequiredTaskStatus(
				{task:asynchronousTask, event:"interrupted"});
				
		taskManagerItem.interrupt();
		
		evaluatorAfterStart.pauseToEvaluateTaskExecution();
	}*/
	
	private var currentEvaluator:TaskExecutionEvaluator;
	private var currentFictiveEventSource:FictiveTask;
	private var currentTask:ITask;
	
	public function testInterruptWhenRunning()
	{
		var testSequence:PauseResumeMethodsSequence 
			= new PauseResumeMethodsSequence(
					this, 
					this.delayInterval,
					[initializeTestInterruptWhenRunning,
					evaluateTaskExecutionAfterStartAndInterrupt, 
					evaluateTaskExecutionAfterInterrupt]);
		
		testSequence.start();
	}
	
	private function initializeTestInterruptWhenRunning()
	{
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		this.currentEvaluator = evaluator;
		
		// prepare asynchonous task:
		var fictiveEventSource:FictiveTask = new FictiveTask();
		this.currentFictiveEventSource = fictiveEventSource;
		
		var eventDescriptor:EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");
		var asynchronousTask:ITask = ExecuteAsyncMethodTask.create(
				eventDescriptor,
				this,
				this.triggerEmptyFunction,
				[]);
		asynchronousTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		asynchronousTask.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		this.currentTask = asynchronousTask;
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				asynchronousTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		taskManagerItem.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		this.currentTaskManagerItem = taskManagerItem;
		
		taskManagerItem.start();
		
		// there are no preconditions, so the taskManagerItem and fictiveTask 
		// should be started, taskManagerItem should be in running state now:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:asynchronousTask, event:"start"});
	}
	
	private function evaluateTaskExecutionAfterStartAndInterrupt()
	{
		this.currentEvaluator.evaluateTaskExecution();
		
		this.currentTaskManagerItem.interrupt();
		
		// but in order to interrupt the taskManagerItem, we need to interrupt 
		// the asynchronousTask:
		this.currentFictiveEventSource.start();
		
		this.currentEvaluator.registerRequiredTaskStatus(
				{task:this.currentTaskManagerItem, event:"interrupted"});
		this.currentEvaluator.registerRequiredTaskStatus(
				{task:this.currentTask, event:"interrupted"});
	}
	
	private function evaluateTaskExecutionAfterInterrupt()
	{	
		this.currentEvaluator.evaluateTaskExecution();
	}
	
	/**
	 * TODO: <code>TaskManagerItem.isRunning()</code> still not implemented, 
	 * and its logic is still not discussed with Barni. 
	 */
	public function testIsRunning()
	{
	}
	
	public function testReplacePreconditionsEventSource()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var fictiveTask:ITask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		// create an accepting taskManagerItem:
		var isAccepting:Boolean = true;
		var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
		taskManagerItem.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveEventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
		
		var fictiveEventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				fictiveEventSource2, 
				"start");
		
		taskManagerItem.addPrecondition(precondition1);
		taskManagerItem.addPrecondition(precondition2);
		
		taskManagerItem.start();
		evaluator.assertTaskStatusRegisterIsEmpty("taskManagerItem is started, but no preconditions were met, so the taskManagerItem should not be in running state");
		
		var fictiveEventSourceNew:FictiveTask = new FictiveTask();
		
		taskManagerItem.replacePreconditionsEventSource(
				fictiveEventSource1, 
				fictiveEventSourceNew);
		
		// try to meet preconditions with old event sources:
		fictiveEventSource1.start();
		fictiveEventSource2.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("precondition1's event source was replaced and precondition1 should not be met yet, so the taskManagerItem should not be in running state");
		
		// meet precondition1 with its new event source:
		fictiveEventSourceNew.start();
		
		// all preconditions were met:
		evaluator.registerRequiredTaskStatus({task:taskManagerItem, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
}